﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Mozlite.Properties;

namespace Mozlite
{
    /// <summary>
    /// 字符串扩展。
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// 将十六进制字符串转换为二进制数组。
        /// </summary>
        /// <param name="hex">十六进制字符串，长度必须被2整除。</param>
        /// <returns>返回二进制数组。</returns>
        public static byte[] FromHex(this string hex)
        {
            if (hex.Length % 2 != 0)
                throw new Exception("The hex is invalid, is not a hex string!");
            byte[] bytes = new byte[hex.Length / 2];
            for (var i = 0; i < hex.Length; i = i + 2)
            {
                bytes[i / 2] = byte.Parse(new string(new[] { hex[i], hex[i + 1] }), NumberStyles.AllowHexSpecifier);
            }
            return bytes;
        }

        /// <summary>
        /// 将基于64位字符串转换为二进制数组。
        /// </summary>
        /// <param name="buffer">用于转换的字符串。</param>
        /// <returns>返回二进制数组。</returns>
        public static byte[] FromBase64(this string buffer)
        {
            return Convert.FromBase64String(buffer);
        }

        /// <summary>
        /// CamelCase格式。
        /// </summary>
        /// <param name="instance">字符串。</param>
        /// <returns>返回CamelCase格式字符串。</returns>
        public static string ToCamelCase(this string instance)
        {
            Guard.IsNotNullOrEmpty(instance, "instance");
            char chr = instance[0];
            return string.Concat(chr.ToString().ToLowerInvariant(), instance.Substring(1));
        }
        /// <summary>
        /// 进行GZip压缩后Base64编码。
        /// </summary>
        /// <param name="instance">当前字符串。</param>
        /// <returns>返回Base64编码字符串。</returns>
        public static string Compress(this string instance)
        {
            byte[] compressed;
            Guard.IsNotNullOrEmpty(instance, "instance");
            byte[] binary = Encoding.UTF8.GetBytes(instance);
            using (MemoryStream ms = new MemoryStream())
            {
                using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress))
                {
                    zip.Write(binary, 0, (int)binary.Length);
                }
                compressed = ms.ToArray();
            }
            byte[] compressedWithLength = new byte[(int)compressed.Length + 4];
            Buffer.BlockCopy(compressed, 0, compressedWithLength, 4, (int)compressed.Length);
            Buffer.BlockCopy(BitConverter.GetBytes((int)binary.Length), 0, compressedWithLength, 0, 4);
            return Convert.ToBase64String(compressedWithLength);
        }

        private static byte[] Decode(string value)
        {
            byte[] numArray;
            try
            {
                numArray = Convert.FromBase64String(value);
            }
            catch (FormatException)
            {
                numArray = new byte[0];
            }
            return numArray;
        }
        /// <summary>
        /// 对GZip压缩后的Base64字符串进行解码。
        /// </summary>
        /// <param name="instance">当前Base64字符串。</param>
        /// <returns>返回解码后的字符串。</returns>
        public static string Decompress(this string instance)
        {
            string str;
            Guard.IsNotNullOrEmpty(instance, "instance");
            byte[] compressed = StringExtensions.Decode(instance);
            if ((int)compressed.Length >= 4)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    int length = BitConverter.ToInt32(compressed, 0);
                    stream.Write(compressed, 4, (int)compressed.Length - 4);
                    byte[] binary = new byte[length];
                    stream.Seek((long)0, SeekOrigin.Begin);
                    using (GZipStream zip = new GZipStream(stream, CompressionMode.Decompress))
                    {
                        try
                        {
                            zip.Read(binary, 0, (int)binary.Length);
                            str = Encoding.UTF8.GetString(binary);
                        }
                        catch (InvalidDataException)
                        {
                            str = string.Empty;
                        }
                    }
                }
                return str;
            }
            else
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 格式化字符串。
        /// </summary>
        /// <param name="instance">当前格式字符串。</param>
        /// <param name="args">格式化参数。</param>
        /// <returns>返回格式化后的字符串。</returns>
        public static string FormatWith(this string instance, params object[] args)
        {
            return string.Format(CultureInfo.CurrentCulture, instance, args);
        }

        /// <summary>
        /// 判断字符串是否为null或" "。
        /// </summary>
        /// <param name="value">当前字符串。</param>
        /// <returns>返回判断结果。</returns>
        public static bool HasValue(this string value)
        {
            return !string.IsNullOrEmpty(value);
        }
        /// <summary>
        /// 返回字符串。
        /// </summary>
        /// <param name="value">当前对象。</param>
        /// <returns>如果空返回<c>null</c>，否则返回当前字符串。</returns>
        public static string ToSafeString(this object value) {
            return value == null ? null : value.ToString();
        }

        /// <summary>
        /// 忽略大小写字符串对比。
        /// </summary>
        /// <param name="instance">字符串。</param>
        /// <param name="comparing">对比的字符串。</param>
        /// <returns>返回对比结果。</returns>
        public static bool IsCaseInsensitiveEqual(this string instance, string comparing)
        {
            return string.Compare(instance, comparing, StringComparison.OrdinalIgnoreCase) == 0;
        }

        /// <summary>
        /// 大小写字符串对比。
        /// </summary>
        /// <param name="instance">字符串。</param>
        /// <param name="comparing">对比的字符串。</param>
        /// <returns>返回对比结果。</returns>
        public static bool IsCaseSensitiveEqual(this string instance, string comparing)
        {
            return string.CompareOrdinal(instance, comparing) == 0;
        }
        /// <summary>
        /// 将文本字符串转换为枚举类型。
        /// </summary>
        /// <typeparam name="T">枚举类型。</typeparam>
        /// <param name="value">枚举字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回的默认类型。</param>
        /// <returns>返回枚举类型实例。</returns>
        public static T ToEnum<T>(this string value, T defaultValue = default(T)) where T : struct
        {
#if DOTNET40
            T retValue;
            if (Enum.TryParse<T>(value, true, out retValue))
                return retValue;
#else
            try
            {
                return (T)Enum.Parse(typeof(T), value, true);
            }
            catch { }
#endif
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为Int32类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static int ToInt32(this string value, int defaultValue = default(int))
        {
            int v;
            if (int.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为Int64类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static long ToInt64(this string value, long defaultValue = default(long))
        {
            long v;
            if (long.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为Int16类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static short ToInt16(this string value, short defaultValue = default(short))
        {
            short v;
            if (short.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为UInt32类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static uint ToUInt32(this string value, uint defaultValue = default(uint))
        {
            uint v;
            if (uint.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为UInt64类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static ulong ToUInt64(this string value, ulong defaultValue = default(ulong))
        {
            ulong v;
            if (ulong.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为UInt16类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static ushort ToUInt16(this string value, ushort defaultValue = default(ushort))
        {
            ushort v;
            if (ushort.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为布尔类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static bool ToBoolean(this string value, bool defaultValue = false)
        {
            bool v;
            if (bool.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为日期类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static DateTime ToDateTime(this string value, DateTime defaultValue = default(DateTime))
        {
            DateTime v;
            if (DateTime.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为decimal类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static decimal ToDecimal(this string value, decimal defaultValue = default(decimal))
        {
            decimal v;
            if (decimal.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为double类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static double ToDouble(this string value, double defaultValue = default(double))
        {
            double v;
            if (double.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 将字符串转换为float类型。
        /// </summary>
        /// <param name="value">字符串。</param>
        /// <param name="defaultValue">如果转换失败，返回默认值。</param>
        /// <returns>返回转换后的值。</returns>
        public static float ToSingle(this string value, float defaultValue = default(float))
        {
            float v;
            if (float.TryParse(value, out v))
                return v;
            return defaultValue;
        }

        /// <summary>
        /// 转换为GUID。
        /// </summary>
        /// <param name="value">要转换的对象实例。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回GUID实例对象。</returns>
        public static Guid ToGuid(this string value, Guid defaultValue = default(Guid))
        {
            try
            {
#if DOTNET40
                Guid retValue;
                if (Guid.TryParse(value, out retValue))
                    return retValue;
#else
                return new Guid(value);
#endif
            }
            catch { }
            return defaultValue;
        }

        /// <summary>
        /// 获取编码。
        /// </summary>
        /// <param name="value">编码对象。</param>
        /// <param name="encoding">编码默认值。</param>
        /// <returns>返回编码实例对象。</returns>
        public static Encoding ToEncoding(this string value, Encoding defaultValue = null)
        {
            if (defaultValue == null)
                defaultValue = Encoding.UTF8;
            try
            {
                return Encoding.GetEncoding(value);
            }
            catch { }
            return defaultValue;
        }

        /// <summary>
        /// 获取版本。
        /// </summary>
        /// <param name="value">版本对象。</param>
        /// <param name="encoding">版本默认值。</param>
        /// <returns>返回版本实例对象。</returns>
        public static Version ToVersion(this string value, Version defaultValue = null)
        {
            try
            {
                return new Version(value);
            }
            catch { }
            return defaultValue;
        }

        /// <summary>
        /// 移除字符串前后空字符串。
        /// </summary>
        /// <param name="str">将要移除的字符串。</param>
        /// <returns>如果字符串为null或为" "，将返回null，否则移除前后空字符串后返回。</returns>
        public static string NullSafeTrim(this string str)
        {
            if (string.IsNullOrEmpty(str))
                return null;
            return str.Trim();
        }

        /// <summary>
        /// 移除字符串前后指定字符。
        /// </summary>
        /// <param name="str">将要移除的字符串。</param>
        /// <param name="trimChars">将要移除的字符集合。</param>
        /// <returns>如果字符串为null，将返回null，否则移除前后指定字符后返回。</returns>
        public static string NullSafeTrim(this string str, params char[] trimChars) {
            if (str == null)
                return str;
            return str.Trim(trimChars);
        }

        /// <summary>
        /// 判断字符串是否为Email地址。
        /// </summary>
        /// <param name="email">当前字符串。</param>
        /// <returns>如果Email地址合法，则返回true。</returns>
        public static bool IsEmail(this string email)
        {
            return emailRegex.IsMatch(email ?? "");
        }

        private static readonly Regex numberRegex = new Regex(@"^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$", RegexOptions.Compiled);
        /// <summary>
        /// 判断是否为数字。
        /// </summary>
        /// <param name="value">字符串类型。</param>
        /// <returns>返回是否为数字。</returns>
        public static bool IsNumeric(this string value)
        {
            if (value == null)
                return false;
            return numberRegex.IsMatch(value);
        }

        #region random
        /// <summary>
        /// 随机生成字符串。
        /// </summary>
        /// <param name="seed">种子字符串。</param>
        /// <param name="length">长度（如果需要不同的字符串，本长度必须小于种子字符串的长度）。</param>
        /// <param name="defferent">是否生成不同的字符。</param>
        /// <returns>返回随机生成的字符串。</returns>
        public static string Random(this string seed, int length = 4, bool defferent = false)
        {
            if (string.IsNullOrEmpty(seed))
                seed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            if (seed.Length < length && defferent)
                throw new Exception(Resources.SeedLengthNotEnough.FormatWith(length));
            List<char> randoms = new List<char>(length);
            var i = 0;
            Random rnd = new Random((int)DateTime.Now.Ticks);
            while (i < length)
            {
                char current = seed[(int)rnd.Next(0, seed.Length)];
                if (defferent)
                {
                    rnd = new Random((int)DateTime.Now.Ticks);
                    if (randoms.Contains(current))
                        continue;
                }
                randoms.Add(current);
                i++;
            }
            return randoms.Join("");
        }
        #endregion

        #region splits
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, char[] separator, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            List<T> list = new List<T>();
            if (!string.IsNullOrEmpty(str))
            {
                foreach (string part in str.Split(separator, options))
                {
                    list.Add(part.To<T>());
                }
            }
            return list;
        }
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, string[] separator = null, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            List<T> list = new List<T>();
            if (!string.IsNullOrEmpty(str))
            {
                if (separator == null)
                    separator = new string[] { "," };
                foreach (string part in str.Split(separator, options))
                {
                    list.Add(part.To<T>());
                }
            }
            return list;
        }
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, char separator, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            return str.Split<T>(new char[] { separator }, options);
        }
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, string separator, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            return str.Split<T>(new string[] { separator }, options);
        }
        #endregion

        #region joins
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join(this NameValueCollection collection, string separator = ",", Func<string, string, string> execute = null)
        {
            if (collection == null)
                return string.Empty;

            StringBuilder builder = new StringBuilder();
            foreach (string key in collection.AllKeys)
            {
                if (builder.Length > 0)
                    builder.Append(separator);
                if (execute == null)
                    builder.AppendFormat("{0}={1}", key, collection[key]);
                else
                    builder.Append(execute(key, collection[key]));
            }
            return builder.ToString();
        }
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join(this IDictionary collection, string separator = ",", Func<string, object, string> execute = null)
        {
            if (collection == null)
                return string.Empty;

            StringBuilder builder = new StringBuilder();
            foreach (string key in collection.Keys)
            {
                if (builder.Length > 0)
                    builder.Append(separator);
                if (execute == null)
                    builder.AppendFormat("{0}={1}", key, collection[key]);
                else
                    builder.Append(execute(key, collection[key]));
            }
            return builder.ToString();
        }
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <typeparam name="TKey">字典键类型。</typeparam>
        /// <typeparam name="TValue">字典值类型。</typeparam>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join<TKey, TValue>(this IDictionary<TKey, TValue> collection, string separator = ",", Func<KeyValuePair<TKey, TValue>, string> execute = null)
        {
            if (collection == null)
                return string.Empty;

            StringBuilder builder = new StringBuilder();
            foreach (var item in collection)
            {
                if (builder.Length > 0)
                    builder.Append(separator);
                if (execute == null)
                    builder.AppendFormat("{0}={1}", item.Key, item.Value);
                else
                    builder.Append(execute(item));
            }
            return builder.ToString();
        }
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join(this IEnumerable collection, string separator = ",", Func<object, string> execute = null)
        {
            if (collection == null)
                return string.Empty;

            StringBuilder builder = new StringBuilder();
            foreach (object value in collection)
            {
                if (value == null)
                    continue;
                if (builder.Length > 0)
                    builder.Append(separator);
                builder.Append(execute == null ? value.ToString() : execute(value));
            }
            return builder.ToString();
        }
        #endregion

        /// <summary>
        /// 截取字符串。
        /// </summary>
        /// <param name="str">需要截取的字符串。</param>
        /// <param name="length">长度。</param>
        /// <param name="ending">截取后末尾添加的字符串。</param>
        /// <returns>返回截取后的字符串。</returns>
        public static string Truncate(this string str, int length, string ending = null)
        {
            if (str == null || str.Length <= length)
                return str;
            return str.Substring(0, length) + ending;
        }

        private static readonly Regex htmlRegex = new Regex("<(.[^>]*)>", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
        /// <summary>
        /// 移除HTML标签，并截取字符串。
        /// </summary>
        /// <param name="str">字符串。</param>
        /// <param name="length">长度，如果小于等于0表示不截取。</param>
        /// <param name="ending">超过长度后结尾字符串。</param>
        /// <param name="trim">移除HTML标签后是否移除字符串前后的空格。</param>
        /// <returns>返回移除处理后的字符串。</returns>
        public static string RemoveHTML(this string str, int length = -1, string ending = null, bool trim = true)
        {
            if (str == null)
                return null;
            str = htmlRegex.Replace(str, string.Empty);
            if (trim)
                str = str.Trim();
            if (length > 0)
                str = str.Truncate(length, ending);
            return str;
        }

        private static readonly Regex emailRegex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);

        private static readonly Regex urlRegex = new Regex(@"^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
        /// <summary>
        /// 判断是否为正确的URL地址。
        /// </summary>
        /// <param name="url">URL地址。</param>
        /// <returns>返回是否为URL地址。</returns>
        public static bool IsUrl(this string url) {
            return urlRegex.IsMatch(url ?? "");
        }

        #region times
        /// <summary>
        /// 生成相同的字符串。
        /// </summary>
        /// <param name="str">字符串。</param>
        /// <param name="times">生成次数。</param>
        /// <returns>返回生成后的字符串。</returns>
        public static string Times(this string str, int times)
        {
            if (str == null || times < 1)
                return null;
            StringBuilder sb = new StringBuilder();
            for (var i = 0; i < times; i++)
            {
                sb.Append(str);
            }
            return sb.ToString();
        }
        /// <summary>
        /// 生成相同的字符。
        /// </summary>
        /// <param name="chr">字符。</param>
        /// <param name="times">生成个数。</param>
        /// <returns>返回生成后的字符串。</returns>
        public static string Times(this char chr, int times)
        {
            if (chr == '\0' || times <= 1)
                return chr + "";
            string str = "";
            for (var i = 0; i < times; i++)
            {
                str += chr;
            }
            return str;
        }
        #endregion
    }
}
